package com.lft.examsys.aop;


import com.lft.examsys.entity.CreditUser;
import com.lft.examsys.entity.User;
import com.lft.examsys.entity.ValidationEntity;
import com.lft.examsys.exception.ValidationFailureException;
import com.lft.examsys.exception.ViewChangeException;
import com.lft.examsys.model.IModel;
import com.lft.examsys.model.ValidationModelAndView;
import com.lft.examsys.service.PermissionService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

@Aspect
@Component
public class ControllerIntercept {
    @Autowired
    private HttpServletRequest req;


    @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping) || @annotation(org.springframework.web.bind.annotation.PostMapping)")
    private void getPointcut() {
    }

    @Pointcut("execution(* com.lft.examsys.controller..*.*(..))")
    private void controllerPointcut() {
    }

    @Around("getPointcut()")
    public Object logAdvice(ProceedingJoinPoint joinPoint) {
        try {
            ModelAndView mv = null;
            boolean valid = true;
            IModel model = null;
            Object[] args = joinPoint.getArgs();
            for (Object arg : args) {
                if (arg instanceof ValidationEntity) {
                    ValidationEntity entity = (ValidationEntity) arg;
                    if (!entity.valid()) {
                        valid = false;
                    }
                } else if (arg instanceof IModel) {
                    model = (IModel) arg;
                }
            }

            if (model == null)
                model = IModel.get();
            model.valid(valid);

            Object obj = joinPoint.proceed();
            if (obj instanceof ModelAndView) {
                mv = (ModelAndView) obj;
            }
            if (obj instanceof ValidationModelAndView) {
                ValidationModelAndView vmv = (ValidationModelAndView) mv;
                try {
                    if (!model.valid())
                        throw new ValidationFailureException("[failure validate entity] invalid parameters");
                    vmv.success();
                } catch (ValidationFailureException failure) {
                    vmv.failure(failure.getMessage());
                } catch (ViewChangeException ignored) {
                }
            }

            if (model.currentView() != null) {
                if (mv == null)
                    mv = new ModelAndView();
                mv.setViewName(model.currentView());
                obj = mv;
            }

            if (mv != null) {
                for (String key : model.keySet()) {
                    mv.addObject(key, model.get(key));
                }
            }

            return obj;
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    @Around("controllerPointcut()")
    public Object addUser(ProceedingJoinPoint joinPoint) {
        try {
            Object o = joinPoint.proceed();
            if (o instanceof ModelAndView) {
                ModelAndView mv = (ModelAndView) o;
                SecurityContext context = SecurityContextHolder.getContext();
                Authentication authentication = context.getAuthentication();

                CreditUser user = authentication.getPrincipal().equals("anonymousUser") ? null : (CreditUser) authentication.getPrincipal();
                mv.addObject("user", user);
            }
            return o;
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }
}
